using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Graphics;
using HappySprite;
using HappySprite.Graphics;
using HappySprite.SceneGraph;

namespace HappyInvaders
{
    class View
    {
        Scene scene;
        PlayerInput playerInput;
        SpriteBatch spriteBatch;
        SpriteFont spriteFont;

        int score;
        int lives;

        bool showGameOver;

        int invadersLeft;
        IEnumerator<string> notes;

        public View()
        {
            // Create new scene
            scene = new Scene();

            // Create sprite batch for text
            spriteBatch = new SpriteBatch(Global.Renderer.Graphics.GraphicsDevice);
            spriteFont = Global.Content.Load<SpriteFont>(@"Fonts\Invader");

            // Configure the camera
            scene.Camera.SetViewportBounds(0f, 0f, Constants.WorldWidth, Constants.WorldHeight);

            // Create the background
            SceneItem<Quad> background = new SceneItem<Quad>();
            background.RenderItem.Width = Constants.WorldWidth;
            background.RenderItem.Height = Constants.WorldHeight;
            background.RenderItem.ImageMap = new ImageMap(@"Textures\background");
            background.Layer = 100;
            background.Local.PositionX = Constants.WorldWidth / 2f;
            background.Local.PositionY = Constants.WorldHeight / 2f;

            scene.Root.Add(background);

            // Kick off invader sounds
            notes = InvaderNotes().GetEnumerator();
            Global.EventScheduler.Schedule(Constants.InvaderCycle, PlayInvaderNote);
        }

        public int Lives
        {
            get { return lives; }
            set { lives = value; }
        }

        public int Score
        {
            get { return score; }
            set { score = value; }
        }

        public bool ShowGameOver
        {
            get { return showGameOver; }
            set { showGameOver = value; }
        }

        public void Draw()
        {
            // Draw scene
            scene.Draw();

            // Draw text
            spriteBatch.Begin();
            spriteBatch.DrawString(spriteFont, "Score:", new Vector2(30f, 0f), Color.Green);
            spriteBatch.DrawString(spriteFont, score.ToString("00000"), new Vector2(90f, 0f), Color.White);
            spriteBatch.DrawString(spriteFont, "Lives:", new Vector2(Constants.ScreenWidth - 100f, 0f), Color.Green);
            spriteBatch.DrawString(spriteFont, lives.ToString(), new Vector2(Constants.ScreenWidth - 40f, 0f), Color.White);

            if (showGameOver)
            {
                Vector2 size, position;
                float y = spriteFont.LineSpacing * 2f;

                size = spriteFont.MeasureString("GAME OVER");
                position = new Vector2(Constants.ScreenWidth / 2f - size.X / 2f, Constants.ScreenHeight / 2f - y / 2f);
                spriteBatch.DrawString(spriteFont, "GAME OVER\n", position, Color.Green);

                size = spriteFont.MeasureString("Press FIRE to start.");
                position = new Vector2(Constants.ScreenWidth / 2f - size.X / 2f, Constants.ScreenHeight / 2f - y / 2f);
                spriteBatch.DrawString(spriteFont, "\nPress FIRE to start.", position, Color.White);
            }

            spriteBatch.End();
        }

        public Visual CreatePlayer()
        {
            return AddToScene(Global.RecycleBin.Create<PlayerVisual>());
        }

        public Visual CreateBomb()
        {
            return AddToScene(Global.RecycleBin.Create<BombVisual>());
        }

        public Visual CreateBullet()
        {
            return AddToScene(Global.RecycleBin.Create<BulletVisual>());
        }

        public Visual CreateExplosion()
        {
            return AddToScene(Global.RecycleBin.Create<ExplosionVisual>());
        }

        public Visual CreateSaucer()
        {
            return AddToScene(Global.RecycleBin.Create<SaucerVisual>());
        }

        public Visual CreateShelter()
        {
            return AddToScene(Global.RecycleBin.Create<ShelterVisual>());
        }

        public Visual CreateInvader(int row)
        {
            int type = (5 - row) / 2;

            switch (type)
            {
                case 0: return AddToScene(Global.RecycleBin.Create<InvaderAlphaVisual>());
                case 1: return AddToScene(Global.RecycleBin.Create<InvaderBetaVisual>());
                default: return AddToScene(Global.RecycleBin.Create<InvaderGammaVisual>());
            }
        }

        public Visual CreateZap()
        {
            return AddToScene(Global.RecycleBin.Create<ZapVisual>());
        }

        public PlayerInput GetPlayerInput()
        {
            // If first time, bind the input class
            if (playerInput == null)
            {
                playerInput = new PlayerInput();
                Global.Input.Add(Keys.A, playerInput, "MoveLeft");
                Global.Input.Add(Keys.Left, playerInput, "MoveLeft");
                Global.Input.Add(Keys.D, playerInput, "MoveRight");
                Global.Input.Add(Keys.Right, playerInput, "MoveRight");
                Global.Input.Add(Keys.Space, playerInput, "Fire");
                Global.Input.Add(Keys.LeftControl, playerInput, "Fire");
            }

            return playerInput;
        }

        internal int InvadersLeft
        {
            get { return invadersLeft; }
            set { invadersLeft = value; }
        }

        Visual AddToScene(Visual visual)
        {
            scene.Root.Add(visual.Item);
            visual.OnAdd(this);
            return visual;
        }

        void PlayInvaderNote()
        {
            if (invadersLeft > 0)
            {
                notes.MoveNext();
                Global.Audio.PlayToEnd(notes.Current);
            }

            float invaderNoteDelay = (4f + invadersLeft / 55f * 36f) * 2f * Constants.InvaderCycle;
            Global.EventScheduler.Schedule(invaderNoteDelay, PlayInvaderNote);
        }

        static IEnumerable<string> InvaderNotes()
        {
            while (true)
            {
                yield return "move1";
                yield return "move2";
                yield return "move3";
                yield return "move4";
            }
        }
    }
}
